/**
 * 使用显示的Lock和Condition对象
 * 
 * @author fireway
 * @since 2019年 02月 24日 星期日 06:47:27 CST
 */
package concurrency;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class Car {
    private Lock mLock = new ReentrantLock();
    
    private Condition mCondition = mLock.newCondition();
    
    private boolean mWaxState = false;

    /**
     * 打蜡
     */
    public /* synchronized */ void waxed() {
        mLock.lock();
        try {
            mWaxState = true;  // Ready to buff
            mCondition.signalAll();
        } finally {
            mLock.unlock();
        }
    }

    public /* synchronized */ void waitForWaxing() throws InterruptedException {
        mLock.lock();
        try {
            while(!mWaxState) {
                mCondition.await();
            }
        } finally {
            mLock.unlock();
        }
    }

    /**
     * 抛光
     */
    public /* synchronized */ void buffed() {
        mLock.lock();
        try {
            mWaxState = false;  // Ready for another coat of wax
            mCondition.signalAll();
        } finally {
            mLock.unlock(); 
        }
    }

    public /* synchronized */ void waitForBuffing() throws InterruptedException {
        mLock.lock();
        try {
            while(mWaxState) {
                mCondition.await();
            }
        } finally {
            mLock.unlock(); 
        }
    }
}

class WaxOn implements Runnable {
    private Car mCar;

    public WaxOn(Car car) {
        mCar = car;
    }

    @Override
    public void run() {
        try {
            while (!Thread.interrupted()) {
                System.out.println("Wax On! in " + Thread.currentThread());
                TimeUnit.MILLISECONDS.sleep(200);
                mCar.waxed();
                mCar.waitForBuffing();
            }
        } catch (InterruptedException e) {
            System.out.println("Exiting via interrupt in " + Thread.currentThread());
        }
        System.out.println("Ending Wax On task in " + Thread.currentThread());
    }
}

class WaxOff implements Runnable {
    private Car mCar;

    public WaxOff(Car car) {
        mCar = car;
    }

    @Override
    public void run() {
        try {
            while (!Thread.interrupted()) {
                mCar.waitForWaxing();
                System.out.println("Wax Off! in " + Thread.currentThread());
                TimeUnit.MILLISECONDS.sleep(200);
                mCar.buffed();
            }
        } catch (InterruptedException e) {
            System.out.println("Exiting via interrupt in " + Thread.currentThread());
        }
        System.out.println("Ending Wax Off task in " + Thread.currentThread());
    }

}

public class WaxOMatic2 {
    public static void main(String[] args) {
        Car car = new Car();
        ExecutorService exec = Executors.newCachedThreadPool();
        exec.execute(new WaxOff(car));
        exec.execute(new WaxOn(car));

        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        exec.shutdownNow();
    }
}
